Completed
Push — master ( 2e96ee...51b9e4 )
by Rain
01:37
created

snowFall.snow   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
nc 7
dl 0
loc 21
rs 7.551
c 0
b 0
f 0
nop 2
1
/*  Snowfall pure js
2
	====================================================================
3
	LICENSE
4
	====================================================================
5
	Licensed under the Apache License, Version 2.0 (the "License");
6
	you may not use this file except in compliance with the License.
7
	You may obtain a copy of the License at
8
9
	   http://www.apache.org/licenses/LICENSE-2.0
10
11
	   Unless required by applicable law or agreed to in writing, software
12
	   distributed under the License is distributed on an "AS IS" BASIS,
13
	   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
	   See the License for the specific language governing permissions and
15
	   limitations under the License.
16
	====================================================================
17
18
	1.0
19
	Wanted to rewrite my snow plugin to use pure JS so you werent necessarily tied to using a framework.
20
	Does not include a selector engine or anything, just pass elements to it using standard JS selectors.
21
22
	Does not clear snow currently. Collection portion removed just for ease of testing will add back in next version
23
24
	Theres a few ways to call the snow you could do it the following way by directly passing the selector,
25
26
		snowFall.snow(document.getElementsByTagName("body"), {options});
27
28
	or you could save the selector results to a variable, and then call it
29
30
		var elements = document.getElementsByClassName('yourclass');
31
		snowFall.snow(elements, {options});
32
33
	Options are all the same as the plugin except clear, and collection
34
35
	values for snow options are
36
37
	flakeCount,
38
	flakeColor,
39
	flakeIndex,
40
	minSize,
41
	maxSize,
42
	minSpeed,
43
	maxSpeed,
44
	round, 		true or false, makes the snowflakes rounded if the browser supports it.
45
	shadow		true or false, gives the snowflakes a shadow if the browser supports it.
46
47
*/
48
49
// Paul Irish requestAnimationFrame polyfill
50
(function(window) {
51
    var lastTime = 0;
52
    var vendors = ['webkit', 'moz'];
53
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
54
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
55
        window.cancelAnimationFrame =
56
          window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
57
    }
58
59
    if (!window.requestAnimationFrame)
60
        window.requestAnimationFrame = function(callback, element) {
61
            var currTime = new Date().getTime();
62
            var timeToCall = window.Math.max(0, 16 - (currTime - lastTime));
63
            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
64
              timeToCall);
65
            lastTime = currTime + timeToCall;
66
            return id;
67
        };
68
69
    if (!window.cancelAnimationFrame)
70
        window.cancelAnimationFrame = function(id) {
71
            clearTimeout(id);
72
        };
73
}(window));
74
75
var snowFall = (function(){
76
	function jSnow(){
77
		// local methods
78
		var	defaults = {
79
			flakeCount : 35,
80
			flakeColor : '#ffffff',
81
			flakeIndex: 999999,
82
			minSize : 1,
83
			maxSize : 2,
84
			minSpeed : 1,
85
			maxSpeed : 5,
86
			round : false,
87
			shadow : false,
88
			collection : false,
89
			image : false,
90
			collectionHeight : 40
91
			},
92
			element = {},
93
			flakes = [],
94
			flakeId = 0,
95
			elHeight = 0,
96
			elWidth = 0,
97
			elTop = 0,
98
			elLeft = 0,
99
			widthOffset = 0,
100
			snowTimeout = 0,
101
			// For extending the default object with properties
102
			extend = function(obj, extObj){
103
				for(var i in extObj){
104
					if(obj.hasOwnProperty(i)){
105
						obj[i] = extObj[i];
106
					}
107
				}
108
			},
109
			// random between range
110
			random = function random(min, max){
111
				return window.Math.round(min + window.Math.random()*(max-min));
112
			},
113
			// Set multiple styles at once.
114
			setStyle = function(element, props)
115
			{
116
				for (var property in props){
117
					element.style[property] = props[property] + ((property === 'width' || property === 'height') ? 'px' : '');
118
				}
119
			},
120
			// snowflake
121
			flake = function(_x, _y, _size, _speed, _id)
122
			{
123
				// Flake properties
124
				this.id = _id;
125
				this.x  = _x + elLeft;
126
				this.y  = _y + elTop;
127
				this.size = _size;
128
				this.speed = _speed;
129
				this.step = 0;
130
				this.stepSize = random(1,10) / 100;
131
132
				if(defaults.collection){
133
					this.target = defaults.collection[random(0,defaults.collection.length-1)];
134
				}
135
136
				var flakeObj = null;
137
138
				if(defaults.image){
139
					flakeObj = new Image();
140
					flakeObj.src = defaults.image;
141
				}else{
142
					flakeObj = window.document.createElement("div");
143
					setStyle(flakeObj, {'background' : defaults.flakeColor});
144
				}
145
146
				flakeObj.className = 'snowfall-flakes';
147
				flakeObj.setAttribute('id','flake-' + this.id);
148
				setStyle(flakeObj, {'width' : this.size, 'height' : this.size, 'position' : 'absolute', 'top' : this.y, 'left' : this.x, 'fontSize' : 0, 'zIndex' : defaults.flakeIndex});
149
150
				// This adds the style to make the snowflakes round via border radius property
151
				if(defaults.round){
152
					setStyle(flakeObj,{'-moz-border-radius' : ~~(defaults.maxSize) + 'px', '-webkit-border-radius' : ~~(defaults.maxSize) + 'px', 'borderRadius' : ~~(defaults.maxSize) + 'px'});
153
				}
154
155
				// This adds shadows just below the snowflake so they pop a bit on lighter colored web pages
156
				if(defaults.shadow){
157
					setStyle(flakeObj,{'-moz-box-shadow' : '1px 1px 1px #555', '-webkit-box-shadow' : '1px 1px 1px #555', 'boxShadow' : '1px 1px 1px #555'});
158
				}
159
160
				window.document.body.appendChild(flakeObj);
161
162
				this.element = flakeObj;
163
164
				// Update function, used to update the snow flakes, and checks current snowflake against bounds
165
				this.update = function(){
166
					this.y += this.speed;
167
168
					if(this.y > (elTop + elHeight) - (this.size  + 6)){
169
						this.reset();
170
					}
171
172
					this.element.style.top = this.y + 'px';
173
					this.element.style.left = ~~this.x + 'px';
174
175
					this.step += this.stepSize;
176
					this.x += window.Math.cos(this.step);
177
178
					if(this.x > (elLeft + elWidth) - widthOffset || this.x < widthOffset){
179
						this.reset();
180
					}
181
				};
182
183
				// Resets the snowflake once it reaches one of the bounds set
184
				this.reset = function(){
185
					this.y = elTop;
186
					this.x = elLeft + random(widthOffset, elWidth - widthOffset);
187
					this.stepSize = random(1,10) / 100;
188
					this.size = random((defaults.minSize * 100), (defaults.maxSize * 100)) / 100;
189
					this.speed = random(defaults.minSpeed, defaults.maxSpeed);
190
				};
191
			},
192
			// this controls flow of the updating snow
193
			animateSnow = function(){
194
				for(var i = 0; i < flakes.length; i += 1){
195
					flakes[i].update();
196
				}
197
				snowTimeout = requestAnimationFrame(function(){animateSnow();});
198
			};
199
		return{
200
			snow : function(_element, _options){
201
				extend(defaults, _options);
202
203
				//init the element vars
204
				element = _element;
205
				elHeight = element.clientHeight,
206
				elWidth = element.offsetWidth;
207
				elTop = element.offsetTop;
208
				elLeft = element.offsetLeft;
209
210
				element.snow = this;
211
212
				// if this is the body the offset is a little different
213
				if(element.tagName.toLowerCase() === 'body'){
214
					widthOffset = 25;
215
				}
216
217
				// Bind the window resize event so we can get the innerHeight again
218
				window.onresize = function(){
219
					elHeight = element.clientHeight;
220
					elWidth = element.offsetWidth;
221
					elTop = element.offsetTop;
222
					elLeft = element.offsetLeft;
223
				};
224
225
				// initialize the flakes
226
				for(var i = 0; i < defaults.flakeCount; i+=1){
227
					flakeId = flakes.length;
228
					flakes.push(new flake(random(widthOffset,elWidth - widthOffset), random(0, elHeight), random((defaults.minSize * 100), (defaults.maxSize * 100)) / 100, random(defaults.minSpeed, defaults.maxSpeed), flakeId));
229
				}
230
				// start the snow
231
				animateSnow();
232
			},
233
			clear : function(){
234
				var flakeChildren = null;
235
236
				if(!element.getElementsByClassName){
237
					flakeChildren = element.querySelectorAll('.snowfall-flakes');
238
				}else{
239
					flakeChildren = element.getElementsByClassName('snowfall-flakes');
240
				}
241
242
				var flakeChilLen = flakeChildren.length;
243
				while(flakeChilLen--){
244
					element.removeChild(flakeChildren[flakeChilLen]);
245
				}
246
247
				flakes = [];
248
				cancelAnimationFrame(snowTimeout);
249
			}
250
		};
251
	};
252
	return{
253
		snow : function(elements, options){
254
			if(typeof(options) === 'string'){
255
				if(elements.length > 0){
256
					for(var i = 0; i < elements.length; i++){
257
						if(elements[i].snow){
258
							elements[i].snow.clear();
259
						}
260
					}
261
				}else{
262
					elements.snow.clear();
263
				}
264
			}else{
265
				if(elements.length > 0){
266
					for(var i = 0; i < elements.length; i++){
267
						new jSnow().snow(elements[i], options);
268
					}
269
				}else{
270
					new jSnow().snow(elements, options);
271
				}
272
			}
273
		}
274
	};
275
})();